﻿using Sgr.DataCategories.Stores;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Sgr.DataCategories.Services
{
    /// <summary>
    /// 默认的数据字典查询实现
    /// </summary>
    public class DefalutCategoryItemsQuery : ICategoryItemsQuery
    {
        private readonly IDataDictionaryStore _dictionaryStore;
        private readonly IEnumerable<IDataDictionaryProvider> _dataDictionaryProviders;

        /// <summary>
        /// 初始化数据字典查询服务
        /// </summary>
        /// <param name="dictionaryStore">数据字典存储</param>
        /// <param name="dataDictionaryProviders">数据字典提供者集合</param>
        public DefalutCategoryItemsQuery(
            IDataDictionaryStore dictionaryStore,
            IEnumerable<IDataDictionaryProvider> dataDictionaryProviders)
        {
            _dictionaryStore = dictionaryStore ?? throw new ArgumentNullException(nameof(dictionaryStore));
            _dataDictionaryProviders = dataDictionaryProviders ?? throw new ArgumentNullException(nameof(dataDictionaryProviders));
        }

        /// <summary>
        /// 异步获取指定类别的所有数据字典项
        /// </summary>
        /// <param name="category">数据字典类别</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>数据字典项的只读字典</returns>
        public Task<IReadOnlyDictionary<string, NameValue>> GetCategoryAsync(string category, CancellationToken cancellationToken = default)
        {
            if (string.IsNullOrWhiteSpace(category))
                throw new ArgumentException("类别名称不能为空", nameof(category));

            return _dictionaryStore.GetOrAddAsync(category, LoadCategoryItemsAsync, cancellationToken);
        }

        /// <summary>
        /// 异步获取指定类别和键的数据字典项
        /// </summary>
        /// <param name="category">数据字典类别</param>
        /// <param name="key">数据字典键</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>数据字典项</returns>
        public async Task<NameValue?> GetItemAsync(string category, string key, CancellationToken cancellationToken = default)
        {
            if (string.IsNullOrWhiteSpace(category))
                throw new ArgumentException("类别名称不能为空", nameof(category));

            if (string.IsNullOrWhiteSpace(key))
                throw new ArgumentException("键名不能为空", nameof(key));

            var items = await GetCategoryAsync(category, cancellationToken);
            return items.TryGetValue(key, out var item) ? item : null;
        }

        #region 辅助方法

        /// <summary>
        /// 获取支持指定类别的数据字典提供者
        /// </summary>
        private IEnumerable<IDataDictionaryProvider> GetSupportedProviders(string category)
        {
            return _dataDictionaryProviders.Where(p => p.IsCategorySupported(category));
        }

        /// <summary>
        /// 异步加载指定类别的数据字典项
        /// </summary>
        /// <param name="category"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        private async Task<IReadOnlyDictionary<string, NameValue>> LoadCategoryItemsAsync(
            string category,
            CancellationToken cancellationToken)
        {
            var providers = GetSupportedProviders(category);
            if (!providers.Any())
            {
                return new Dictionary<string, NameValue>();
            }

            var allItems = new List<NameValue>();
            foreach (var provider in providers)
            {
                try
                {
                    var items = await provider.GetItemsAsync(category, cancellationToken).ConfigureAwait(false);
                    if (items != null && items.Any())
                    {
                        allItems.AddRange(items);
                    }
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine($"从提供者加载类别 {category} 时出错: {ex.Message}");
                }
            }

            // 合并并去重，使用最后一个同键的项
            var estimatedCapacity = allItems.Count;
            var result = new Dictionary<string, NameValue>(estimatedCapacity);

            foreach (var group in allItems.GroupBy(i => i.Value))
            {
                result[group.Key] = group.Last();
            }
            return result;
        }

        #endregion 辅助方法
    }
}